package br.com.farmabid.usuario;

import java.io.DataInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.ResourceBundle;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.binary.Base64;

import br.com.caelum.vraptor.Controller;
import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.observer.download.ByteArrayDownload;
import br.com.caelum.vraptor.observer.download.Download;
import br.com.caelum.vraptor.observer.upload.UploadSizeLimit;
import br.com.caelum.vraptor.observer.upload.UploadedFile;
import br.com.farmabid.cadastro.Farmacia;
import br.com.farmabid.cadastro.FarmaciaDAO;
import br.com.farmabid.component.PasswordEncryptionService;
import br.com.farmabid.component.StringUteis;
import br.com.farmabid.controller.BasicController;
import br.com.farmabid.controller.HomeController;

@Controller
public class UsuarioController extends BasicController {
    @Inject private UsuarioDAO usuarioDAO;
    @Inject private FarmaciaDAO farmaciaDAO;
   
    public UsuarioController(Result result, ResourceBundle bundle,
			UsuarioDAO usuarioDAO, FarmaciaDAO farmaciaDAO) {
    	this.result = result;
		this.bundle = bundle;
		this.usuarioDAO = usuarioDAO;
		this.farmaciaDAO = farmaciaDAO;
	}

    public UsuarioController(){}
    
	@PostConstruct
    public void init(){
        injetaUsuario();
    }
   
    @Path(value = "/" + USUARIO)
    @Get
    public void usuario(Integer quantidadeRegistros, Integer pagina) {
    	List<Usuario> listaUsuario = usuarioDAO.recuperaUsuarios(null, null);
    	result.include("totalRegistros", listaUsuario.size());
    	listaUsuario = usuarioDAO.recuperaUsuarios(pagina, quantidadeRegistros);
        result.include("listaUsuarios", listaUsuario);
    	if(pagina == null){
    		pagina = 1;
    	}
    	result.include("pagina", pagina);
    	Integer totalPaginas = 1;
    	if(quantidadeRegistros != null){
    		totalPaginas =  (listaUsuario.size() + (quantidadeRegistros - 1) ) / quantidadeRegistros;
    	}
		result.include("totalPaginas", totalPaginas);
    }
   
    @Path(value = "/" + USUARIO + "/" + NOVO)
    @Get
    public void novo() {
    	if(!resultPossui(USUARIO)){
    		result.include(USUARIO, new Usuario());
    	}
    	result.include("listaFarmacias", farmaciaDAO.recuperaFarmaciaSemUsuario());
        result.include("listaTipos", usuarioDAO.recuperaTodos(TipoUsuario.class));
    }
   
    @Path(value = "/" + USUARIO + "/" + EDITAR)
    @Post
    public void editar(String id){
    	if(!StringUteis.isEmpty(id)){
	        Usuario usuario = (Usuario) usuarioDAO.find(Usuario.class, Integer.parseInt(id));
	        result.include(USUARIO, usuario);
	        List<Farmacia> listaFarmacias = farmaciaDAO.recuperaFarmaciaSemUsuario();
        	if(usuario.getFarmacia() != null && usuario.getFarmacia().size() > 0){
        		listaFarmacias.add(usuario.getFarmacia().get(0));
        		result.include("farmaciaId", usuario.getFarmacia().get(0).getId());
        	}
        	result.include("listaFarmacias", listaFarmacias);
	        result.include("listaTipos", usuarioDAO.recuperaTodos(TipoUsuario.class));
    	} else {
    		mensagemErro("erro.ao.recuperar");
    	}
    }
    
    @Path("/" + USUARIO + "/imagem/{id}")  
	public Download imagem(Integer id) {  
    	Usuario pi = (Usuario) farmaciaDAO.find(Usuario.class, id);  
	     return new ByteArrayDownload(pi.getImagem(), "image/png", "imagem1");  
	}
   
    @Path(value = "/"  + USUARIO + "/" + EXCLUIR)
    @Post
    public void excluir(String id){
    	if(!StringUteis.isEmpty(id)){
	        Usuario usuario = (Usuario) usuarioDAO.find(Usuario.class, Integer.parseInt(id));
	        usuarioDAO.remove(usuario);
	        mensagemSucesso("usuario.excluido.sucesso");
    	} else {
    		mensagemErro("erro.ao.excluir");
    	}
        redirect();
    }
   
    @Path(value = "/"  + USUARIO + "/" + GRAVAR)
    @Post
    @UploadSizeLimit(sizeLimit=40 * 1024 * 1024, fileSizeLimit=10 * 1024 * 1024)
    public void gravar(Usuario usuario, UploadedFile nomeImagem, String ativo){
    	if(usuario == null){
    		mensagemErro("erro.ao.gravar");
    	} else {
    		if(StringUteis.isEmpty(usuario.getNome())){
    			mensagemErro("erro.nome.usuario.obrigatorio");
    		}
    		if(StringUteis.isEmpty(usuario.getEmail())){
    			mensagemErro("erro.email.usuario.obrigatorio");
    		}
    		if(null == usuario.getId()){
    			if(StringUteis.isEmpty(usuario.getSenha())){
        			mensagemErro("erro.senha.usuario.obrigatorio");
        		}
    			if(!regraValidacaoSenha(usuario.getSenha())){
    				mensagemErro("erro.senha.invalida");
    			}
    		}
    	}
    	if(resultPossui(ERROR) && resultPossuiConteudo(ERROR)){
    		result.include(USUARIO, usuario);
    		result.redirectTo(UsuarioController.class).novo();
    		return;
    	}
        if(usuario.getId() != null){
        	Usuario temp = (Usuario) usuarioDAO.find(Usuario.class, usuario.getId());
        	if(temp == null){
        		//
        	} else {
        		String chave = "";
        		String senha = "";
        		String cpf = temp.getCpf();
        		if(!StringUteis.isEmpty(usuario.getSenha()) && regraValidacaoSenha(usuario.getSenha())){
        			geraChaveCriptografada(usuario);
        			chave = usuario.getChave();
        			senha = usuario.getSenha();
        		} else {
        			chave = temp.getChave();
        			senha = temp.getSenha();
        		}
        		try {
                    BeanUtils.copyProperties(temp, usuario);
                } catch (IllegalAccessException e) {
                	mensagemErro("erro.ao.gravar");
                } catch (InvocationTargetException e) {
                	mensagemErro("erro.ao.gravar");
                }
				if("S".equals(ativo)){
					temp.setAtivo(1);
				} else {
					temp.setAtivo(0);
				}
				temp.setTentativas(0);
				temp.setCpf(cpf);
				temp.setChave(chave);
				temp.setSenha(senha);
				temp.setTipo((TipoUsuario) usuarioDAO.find(TipoUsuario.class, usuario.getTipo().getId()));
				usuarioDAO.update(temp);
				mensagemSucesso("usuario.atualizado.sucesso");
        	}
        } else {
        	if(!StringUteis.isCPF(StringUteis.limpaString(usuario.getCpf()))){
    			mensagemErro("erro.cpf.invalido");
    		}
        	Usuario pre = usuarioDAO.recuperaUsuarioPorEmail(usuario.getEmail());
            if(pre != null){
            	mensagemErro("erro.email.ja.existe");
            }
            pre = usuarioDAO.recuperaUsuarioPorCPF(usuario.getCpf());
            if(pre != null){
            	mensagemErro("erro.cpf.ja.existe");
            }
            if(resultPossui(ERROR) && resultPossuiConteudo(ERROR)){
        		result.include(USUARIO, usuario);
        		result.redirectTo(UsuarioController.class).novo();
        		return;
        	}
            if("S".equals(ativo)){
            	usuario.setAtivo(1);
            } else {
            	usuario.setAtivo(0);
            }
            if(nomeImagem != null){
            	byte[] imgDataBa = new byte[(int)nomeImagem.getSize()];
				DataInputStream dataIs = new DataInputStream(nomeImagem.getFile());
				try {
					dataIs.readFully(imgDataBa);
				} catch (IOException e) {
					e.printStackTrace();
				}
				usuario.setNomeFoto(nomeImagem.getFileName());
				usuario.setImagem(imgDataBa);
            }
            usuario.setTentativas(0);
            usuario.setAtivo(1);
            geraChaveCriptografada(usuario);
            usuario.setTipo((TipoUsuario) usuarioDAO.find(TipoUsuario.class, usuario.getTipo().getId()));
            usuarioDAO.save(usuario);
            mensagemSucesso("usuario.gravado.sucesso");
        }
        redirect();
    }

	private void geraChaveCriptografada(Usuario usuario) {
		PasswordEncryptionService pes = new PasswordEncryptionService();
		
		try {
			byte[] salt = pes.generateSalt();
			usuario.setChave(Base64.encodeBase64String(salt));
			usuario.setSenha(Base64.encodeBase64String(pes.getEncryptedPassword(usuario.getSenha(), salt)));
		} catch (Exception e) {
			mensagemErro("erro.ao.gravar");
		}
	}
	
	private Boolean regraValidacaoSenha(String senha){
		String pattern = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&+=])(?=\\S+$).{8,}$";
		return senha.matches(pattern);
	}
   
    @Path(value = "/"  + USUARIO + "/gravarSenha")
    @Post
    public void gravarSenha(Usuario usuario){
    	if(usuario != null){
	        Usuario pre = (Usuario) usuarioDAO.find(Usuario.class, usuario.getId());
	        if(pre != null){
	            geraChaveCriptografada(usuario);
	            usuarioDAO.update(pre);
	            mensagemSucesso("senha.alterada.sucesso");
	        } else {
	        	mensagemErro("erro.ao.gravar");
	        }
    	} else {
    		mensagemErro("erro.ao.gravar");
    	}
        result.redirectTo(HomeController.class).login();
    }

    @Override
    protected void redirect() {
        result.redirectTo(UsuarioController.class).usuario(null, null);
    }

}